/*
 * @Description: 前端数字精确计算函数
 *  
 * @Date: 2021-03-02 10:42:00
 */

class calcFun {
	num = 0
	constructor(num) {
		this.num = num || ''
	}
	// 是否是整数
	isInteger(obj) {
		return Math.floor(obj) === obj
	}
	// 是否是单个参数
	isINstannce(...arg) {
		return arg.length === 1 ? true : false
	}
	/*
	 * 将一个浮点数转成整数，返回整数和倍数。如 3.14 >> 314，倍数是 100
	 * @param floatNum {number} 小数
	 * @return {object}
	 *   {times:100, num: 314}
	 */
	toInteger(floatNum) {
		var ret = {
			times: 1,
			num: 0,
		}
		if (this.isInteger(floatNum)) {
			ret.num = floatNum
			return ret
		}
		var strfi = floatNum + ''
		var dotPos = strfi.indexOf('.')
		var len = strfi.substr(dotPos + 1).length
		var times = Math.pow(10, len)
		var intNum = parseInt(floatNum * times + 0.5, 10)
		ret.times = times
		ret.num = intNum
		return ret
	}
	/*
	 * 核心方法，实现加减乘除运算，确保不丢失精度
	 * 思路：把小数放大为整数（乘），进行算术运算，再缩小为小数（除）
	 *
	 * @param a {number} 运算数1
	 * @param b {number} 运算数2
	 * @param op {string} 运算类型，有加减乘除（add/subtract/multiply/divide）
	 *
	 */
	operation(a, b, op) {
		var o1 = this.toInteger(a)
		var o2 = this.toInteger(b)
		var n1 = o1.num
		var n2 = o2.num
		var t1 = o1.times
		var t2 = o2.times
		var max = t1 > t2 ? t1 : t2
		var result = null
		switch (op) {
			case 'add':
				if (t1 === t2) {
					// 两个小数位数相同
					result = n1 + n2
				} else if (t1 > t2) {
					// o1 小数位 大于 o2
					result = n1 + n2 * (t1 / t2)
				} else {
					// o1 小数位 小于 o2
					result = n1 * (t2 / t1) + n2
				}
				return result / max
			case 'subtract':
				if (t1 === t2) {
					result = n1 - n2
				} else if (t1 > t2) {
					result = n1 - n2 * (t1 / t2)
				} else {
					result = n1 * (t2 / t1) - n2
				}
				return result / max
			case 'multiply':
				result = (n1 * n2) / (t1 * t2)
				return result
			case 'divide':
				result = (n1 / n2) * (t2 / t1)
				return result
		}
	}
	backSelf(arg, type) {
		if (arg.length === 1) {
			this.num = this.operation(this.num, arg[0], type)
			return this
		}
		return this.operation(...arg, type)
	}
	// 加
	add(...arg) {
		let type = 'add'
		return this.backSelf(arg, type)
	}
	// 减
	sub(...arg) {
		let type = 'subtract'
		return this.backSelf(arg, type)
	}
	// 乘
	mul(...arg) {
		let type = 'multiply'
		return this.backSelf(arg, type)
	}
	// 除
	div(...arg) {
		let type = 'divide'
		return this.backSelf(arg, type)
	}
	end() {
		return this.num
	}
}

const numCalc = {
	start(num) {
		return new calcFun(num)
	},
	// 加
	add(a, b) {
		return new calcFun().add(a, b)
	},
	// 减
	sub(a, b) {
		return new calcFun().sub(a, b)
	},
	// 乘
	mul(...arg) {
		return new calcFun().mul(...arg)
	},
	// 除
	div(a, b) {
		return new calcFun().div(a, b)
	},
	floatFix(num, s = 4) {
		var times = Math.pow(10, s)
		let a = Math.floor(numCalc.mul(num, times))
		return Number(numCalc.div(a, times))
	},
	// 多数相乘 向下取4位小数
	computedMulToDecimal4(...arg) {
		let result = numCalc.start(1)
		arg.forEach((item) => {
			result.mul(item)
		})
		return this.floatFix(result.num, 4)
	},
	// 判断2个数字是否可以整除
	isWholeDiv(a, b) {
    if (!a||!b) {
      return false
    }
		let s = this.div(a, b).toString()
		return Boolean(!(s.indexOf('.') > -1))
	},
  // 数字转字符串 补0
	decimalToStringZero(x, decimal = 2) {
		let times = Math.pow(10, decimal)
		var f = parseFloat(x)
		if (isNaN(f)) {
			return x
		}
		var f = numCalc.div(Math.floor(numCalc.mul(x, times)), times)
		var s = f.toString()
		var rs = s.indexOf('.')
		if (rs < 0) {
			rs = s.length
			s += '.'
		}
		while (s.length <= rs + decimal) {
			s += '0'
		}
		return s
	},
  decimalToStringZero4(x){
    return this.decimalToStringZero(x, 4)
  },
  decimalToStringZero2(x){
    return this.decimalToStringZero(x, 2)
  }
}
export default numCalc

console.log('計算結果', numCalc.decimalToStringZero2(4.02))
numCalc.mul(0.0904, 8)
// numCalc.start(12.31).div(2).end()
console.log('計算結果222', numCalc.isWholeDiv(0.436, 0.218))
